use super::{tiles, RenderState, SurfaceId};
use skia_safe::{self as skia, Rect};

#[cfg(target_arch = "wasm32")]
use crate::run_script;

const DEBUG_SCALE: f32 = 0.2;

fn get_debug_rect(rect: Rect) -> Rect {
    skia::Rect::from_xywh(
        100. + rect.x() * DEBUG_SCALE,
        100. + rect.y() * DEBUG_SCALE,
        rect.width() * DEBUG_SCALE,
        rect.height() * DEBUG_SCALE,
    )
}

#[allow(dead_code)]
fn render_debug_view(render_state: &mut RenderState) {
    let mut paint = skia::Paint::default();
    paint.set_style(skia::PaintStyle::Stroke);
    paint.set_color(skia::Color::GREEN);
    paint.set_stroke_width(1.);

    let rect = get_debug_rect(render_state.viewbox.area);
    render_state
        .surfaces
        .canvas(SurfaceId::Debug)
        .draw_rect(rect, &paint);
}

#[allow(dead_code)]
pub fn render_debug_cache_surface(render_state: &mut RenderState) {
    let canvas = render_state.surfaces.canvas(SurfaceId::Debug);
    canvas.save();
    canvas.scale((0.1, 0.1));
    render_state
        .surfaces
        .draw_into(SurfaceId::Cache, SurfaceId::Debug, None);
    render_state.surfaces.canvas(SurfaceId::Debug).restore();
}

pub fn render_wasm_label(render_state: &mut RenderState) {
    let canvas = render_state.surfaces.canvas(SurfaceId::Target);
    let skia::ISize { width, height } = canvas.base_layer_size();
    let mut paint = skia::Paint::default();
    paint.set_color(skia::Color::GRAY);

    let str = if render_state.options.is_debug_visible() {
        "WASM RENDERER (DEBUG)"
    } else {
        "WASM RENDERER"
    };
    let (scalar, _) = render_state.fonts.debug_font().measure_str(str, None);
    let p = skia::Point::new(width as f32 - 25.0 - scalar, height as f32 - 25.0);

    let debug_font = render_state.fonts.debug_font();
    canvas.draw_str(str, p, debug_font, &paint);
}

#[allow(dead_code)]
pub fn render_debug_tiles_for_viewbox(render_state: &mut RenderState) {
    let tiles::TileRect(sx, sy, ex, ey) = render_state.tile_viewbox.interest_rect;
    let canvas = render_state.surfaces.canvas(SurfaceId::Debug);
    let mut paint = skia::Paint::default();
    paint.set_color(skia::Color::RED);
    let str_rect = format!("{} {} {} {}", sx, sy, ex, ey);

    let debug_font = render_state.fonts.debug_font();
    canvas.draw_str(str_rect, skia::Point::new(100.0, 150.0), debug_font, &paint);
}

// Renders the tiles in the viewbox
#[allow(dead_code)]
pub fn render_debug_viewbox_tiles(render_state: &mut RenderState) {
    let scale = render_state.get_scale();
    let canvas = render_state.surfaces.canvas(SurfaceId::Debug);
    let mut paint = skia::Paint::default();
    paint.set_style(skia::PaintStyle::Stroke);
    paint.set_color(skia::Color::MAGENTA);
    paint.set_stroke_width(1.);

    let tile_size = tiles::get_tile_size(scale);
    let tiles::TileRect(sx, sy, ex, ey) =
        tiles::get_tiles_for_rect(render_state.viewbox.area, tile_size);
    let str_rect = format!("{} {} {} {}", sx, sy, ex, ey);

    let debug_font = render_state.fonts.debug_font();
    canvas.draw_str(str_rect, skia::Point::new(100.0, 100.0), debug_font, &paint);

    let tile_size = tiles::get_tile_size(scale);
    for y in sy..=ey {
        for x in sx..=ex {
            let rect = Rect::from_xywh(
                x as f32 * tile_size,
                y as f32 * tile_size,
                tile_size,
                tile_size,
            );
            let debug_rect = get_debug_rect(rect);
            let p = skia::Point::new(debug_rect.x(), debug_rect.y() - 1.);
            let str = format!("{}:{}", x, y);
            let debug_font = render_state.fonts.debug_font();
            paint.set_style(skia::PaintStyle::Fill);
            canvas.draw_str(str, p, debug_font, &paint);
            canvas.draw_rect(debug_rect, &paint);
        }
    }
}

pub fn render(render_state: &mut RenderState) {
    // DEBUG VIEWBOX - green rect - buggy?
    // render_debug_view(render_state);

    // DEBUG VIEWBOX TILES - magenta - buggy?
    // render_debug_viewbox_tiles(render_state);

    // DEBUG CACHE SURFACE - noisy - ?
    // render_debug_cache_surface(render_state);

    render_state.surfaces.draw_into(
        SurfaceId::Debug,
        SurfaceId::Target,
        Some(&skia::Paint::default()),
    );
}

pub fn render_workspace_current_tile(
    render_state: &mut RenderState,
    prefix: String,
    tile: tiles::Tile,
    rect: skia::Rect,
) {
    let canvas = render_state.surfaces.canvas(SurfaceId::Debug);
    let mut p = skia::Paint::default();
    p.set_stroke_width(2.);
    p.set_style(skia::PaintStyle::Stroke);
    canvas.draw_rect(rect, &p);

    let tile_position_origin = skia::Point::new(rect.x() + 10., rect.y() + 20.);
    p.set_style(skia::PaintStyle::Fill);
    let str = format!("{prefix} {}:{}", tile.x(), tile.y());
    let mut debug_font = render_state.fonts.debug_font().clone();
    debug_font.set_size(16.);
    canvas.draw_str(str, tile_position_origin, &debug_font, &p);
}

pub fn render_debug_shape(
    render_state: &mut RenderState,
    shape_selrect: Option<skia::Rect>,
    shape_extrect: Option<skia::Rect>,
) {
    let canvas = render_state.surfaces.canvas(SurfaceId::Debug);

    let mut paint = skia::Paint::default();
    paint.set_style(skia::PaintStyle::Stroke);
    paint.set_color(skia::Color::RED);
    paint.set_stroke_width(1.);

    if let Some(rect) = shape_selrect {
        canvas.draw_rect(rect, &paint);
    }

    if let Some(rect) = shape_extrect {
        paint.set_color(skia::Color::BLUE);
        canvas.draw_rect(rect, &paint);
    }
}

#[cfg(target_arch = "wasm32")]
#[allow(dead_code)]
pub fn console_debug_surface(render_state: &mut RenderState, id: SurfaceId) {
    let base64_image = render_state.surfaces.base64_snapshot(id);

    run_script!(format!("console.log('%c ', 'font-size: 1px; background: url(data:image/png;base64,{base64_image}) no-repeat; padding: 100px; background-size: contain;')"))
}

#[allow(dead_code)]
#[cfg(target_arch = "wasm32")]
pub fn console_debug_surface_rect(render_state: &mut RenderState, id: SurfaceId, rect: skia::Rect) {
    let int_rect = skia::IRect::from_ltrb(
        rect.left as i32,
        rect.top as i32,
        rect.right as i32,
        rect.bottom as i32,
    );

    let base64_image = render_state.surfaces.base64_snapshot_rect(id, int_rect);

    if let Some(base64_image) = base64_image {
        run_script!(format!("console.log('%c ', 'font-size: 1px; background: url(data:image/png;base64,{base64_image}) no-repeat; padding: 100px; background-size: contain;')"))
    }
}
